/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * bocciawii
 * Copyright (C) Grupo de trabajo ULE 2010 <ulewii@googlegroups.com>
 * 
 * teclado is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * teclado is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _LINKED_CONTAINER_H_
#define _LINKED_CONTAINER_H_

#include "elemento.h"
#include "barra.h"
#include "mensaje.h"
#include "GL/glu.h"
#include "GL/gl.h"
#define MAX_ELEMS 20
#define STYLE_NO_BORDER 1
#define STYLE_BORDER 2
#define STYLE_NO_BG 4
#define STYLE_BG 8
#define STYLE_SOFT 16
#define STYLE_HARD 32

typedef struct
{
	int x_inicio;
	int y_inicio;
	int x_final;
	int y_final;
	int ancho;
	int alto;
	int centro_x;
	int centro_y;
} cont_alloc;

/**
 *@brief Contenedor simple
 *
 * Esta clase implementa un contenedor simple de cualesquiera elementos.
 *
 * La diferencia básica entre este contenedor o los super contenedores, es que 
 * éste es el básico para mostrar elementos. Dicho sencillamente, agrupa
 * elementos en una misma zona, con un fondo común, unidos, de ahí Linked.
 *
 * Este contenedor agregará elementos por orden (lo que primero agregues irá primero)
 * y siempre los mostrará todos (no se pueden ocultar), pero no quiere decir que 
 * el container no pueda ser ocultado completamente.
 *
 * Está pensado para ser sencillo y rápido de utilizar, y sólo ofrece una funcionalidad
 * básica, aunque ampliarlo no debería ser excesivamente difícil, como añadir más
 * opciones de agregado (actualmente el contenedor funciona como una tabla de una columna)
 * alineación de objetos (actualmente todos los elementos se alinean en el centro),
 * y más opciones de imagen.
 *
 * No obstante, se ha conservado la funcionalidad de las imágenes de los elementos
 * para los contenedores (con tres alineaciones diferentes IMG_ALIGN_BELOW_RIGHT,
 * IMG_ALIGN_ABOVE_RIGHT y IMG_ALIGN_CENTER), añadir más tampoco sería cuestión de
 * mucho pensar, pero para lo que nos ocupa es más que de sobra.
 *
 * También admite flags de estilo (fácilmente ampliables si también se implementan
 * en el dibujado. Estos flags son STYLE_BORDER, STYLE_BG, STYLE_SOFT y sus 
 * respectivos negados. STYLE_BORDER y STYLE_BG son autoexplicativos, STYLE_SOFT
 * y STYLE_HARD determinan la forma del contenedor. Para STYLE_HARD el contenedor
 * será dibujado como un cuadrado normal, para STYLE_SOFT se dibujará con los 
 * bordes redondeados.
 *
 * Esta clase además sirve de base para <code>Boton</code> que es otro Linked container
 * con una funcionalidad orientada a menús y a recibir eventos, etcétera.
 */
class LinkedContainer
{
public:

	/**
	 * @brief Constructor simple. Arranca el container, guarda la resolución de pantalla.
	 *
	 * El constructor básico. Inicializa las variables y guarda la resolución de la ventana.
	 * Esto último sirve para determinar si un container se sale de la pantalla,
	 * con lo que podremos corregirlo y ajustarlo para dejarlo dentro de la pantalla
	 * completamente.
	 *
	 */
	LinkedContainer(int x, int y);
	virtual ~LinkedContainer();

	/**
	 * @brief Setter para el color de fondo
	 *
	 * Asigna un color de fondo al container
	 * @param color float[3] con R, G y B
	 */
	void SetBGColor(float* color);

	
	/**
	 * @brief Setter para la transparencia del fondo
	 *
	 * Asigna la transparencia del fondo del contenedor
	 * @param trans 1 es opaco, 0 es transparente
	 */
	void SetBGTransparency(float trans);
	
	/**
	 * @brief Asigna una imagen al fondo del container
	 *
	 * Éste es un proceso independiente a si el elemento es una barra o es un mensaje
	 * Por esto se puede implementar en la base virtual. Actualmente los únicos tipos
	 * de imágenes soportados por el motor son, al igual que con <code>ElementoEstacionario</code>
	 * .PNG con o sin transparencia.
	 * 
	 * @param nombre Nombre del archivo .PNG (la ruta se determina por <code>rutas.h</code>)
	 * @param tam_x El ancho de la imagen (-1, por defecto, para utilizar la imagen al completo)
	 * @param tam_y El alto de la imagen (-1, por defecto, para utilizar la imagen al completo)
	 * @param img_align IMG_ALIGN_LEFT (por omisión) ó IMG_ALIGN_RIGHT ó IMG_ALIGN_ABOVE ó IMG_ALIGN_LEFT
	 */
	void SetBGImage(std::string nombre, 
					int tam_x = -1, 
					int tam_y = -1, 
					int img_align = IMG_ALIGN_BELOW);

	/**
	 * @brief Setter para los flags de estilo
	 *
	 * Asigna el estilo del contenedor
	 * @param flags Int con los diferentes estilos, pueden ser OR'ed
	 */
	void SetStyle(int flags);

	
	/**
	 * @brief Setter para la visibilidad del contenedor
	 *
	 * Asigna la visibilidad del contenedor
	 * @param visible 1 para que se dibuje, 0 para no.
	 */
	void SetVisible (int visible);
	/**
	 * @brief Getter para la visibilidad del contenedor
	 *
	 * Obtiene la visibilidad del contenedor
	 * @return 0 si es invisible, 1 si es visible
	 */
	int EsVisible ();

	
	/**
	 * @brief Setter para el resaltado del container
	 *
	 * Asigna el highlight del container. Más útil en <code>Boton</code>
	 * @param highlight 1 para resaltado, 0 para no
	 */
	void SetHighlight(int highlight);
		
	/**
	 * @brief Getter para el resaltado del container
	 *
	 * Obtiene la visibilidad del contenedor
	 * @return 0 si no está resaltado, 1 si lo está
	 */
	int EsHighlight();

	
	/**
	 * @brief Agregar hijos al container
	 *
	 * Agrega un hijo al container en la primera posición libre.
	 * Este hijo se mostrará siempre, si se agrega un nuevo hijo, se requerirá
	 * otro Pack() para que se muestre correctamente.
	 * @param elem Elemento* a agregar.
	 */
	void Append(Elemento* elem);

	
	/**
	 * @brief Empaquetar contenedor y sus hijos
	 *
	 * Este procedimiento computará el espacio necesario por los hijos del container,
	 * calculará su centro, y calculará los centros de los hijos.
	 * Con estos datos, computará sus boundings, y hará Pack() sobre sus hijos.
	 * @param centro_x El punto donde estará el centro del container
	 * @param centro_y El punto donde estará el centro del container
	 */
	void Pack(int centro_x, int centro_y);

	
	/**
	 * @brief Buscar un hijo
	 *
	 * Pasará por todos sus elementos internos buscando al que tenga la ID dada
	 * Si lo encuentra lo devolverá, si no NULL.
	 * @param id ID del elemento a buscar
	 * @return Referencia al elemento que buscábamos, o NULL en otro caso.
	 */
	Elemento* GetElemByID(std::string id);

	
	/**
	 * @brief Dibujado del container y sus hijos
	 *
	 * Este procedimiento dibujará el container, y justo encima, sus hijos.
	 */
	void Dibujar();

	

	/**
	 * @brief Obtener el centro del container
	 *
	 *
	 *
	 * @return int[2] con el centro_x, centro_y
	 */
	int* GetCenter();

	virtual std::string GetID();

	virtual std::string OnDir(int dir);
	virtual void ToDir(int dir, std::string id);

	virtual void SetSelectable(int selectable);
	virtual int IsSelectable();

	

protected:
	/// Color de fondo
	float _bgColor[3];
	/// Referencia GL de imagen de fondo
	GLuint _bgImage;
	/// Transparencia del fondo
	float _transparency;
	/// Estilo del contenedor
	int _style;
	/// Visibilidad del contenedor
	int _visible;
	/// Posición en la que agregar elementos
	int _posActual;
	/// Ancho de la pantalla
	int _pantallaX;
	/// Alto de la pantalla
	int _pantallaY;
	/// Espacio que necesitará el elemento
	cont_alloc _posGlobal;

	/// Espacio a dejar entre elementos (actualmente hardcoded)
	int _spacing;

	
	/// 1 si está resaltado, 0 de lo contrario
	int _highlighted;


	/// Posición de la imagen, si la tuviera
	img_alloc _posImg;

	
	/// Hijos
	Elemento *elems[MAX_ELEMS];
private:

	SDL_Surface* LoadPNG (std::string ruta);

	void DibujarSuavizado(GLenum mode);
	void DibujarDuro(GLenum mode);
};

#endif // _LINKED_CONTAINER_H_
